# -*- coding: utf-8 –*-
import datetime

from mongoengine import StringField, IntField, EmailField, BooleanField, URLField, FloatField, \
    DateTimeField, ListField, EmbeddedDocumentField, ObjectIdField, DictField, PointField, \
    ReferenceField, Document, EmbeddedDocument, URLField, DecimalField, signals, queryset_manager

from .destination import Destination
from app.models.base import BaseDocument
from .mtu import Mtu
from app.constants import MTU_TYPE
from app.utils import safe_int, smart_str

import json


class Classify(Document):
    """
    产品类型。比如保险、门票、WiFi、一日游等
    """
    name = StringField(unique=True)
    name_en = StringField(null=True)  # 供应商英文名称
    date_added = DateTimeField(default=datetime.datetime.utcnow)
    is_active = BooleanField(verbose_name=u'是否启用', default=True)
    meta = {
        'collection': 'vacation_classify',
    }


class Supplier(Document):
    """
    供应商
    """
    name = StringField(unique=True)
    name_en = StringField(null=True)  # 供应商英文名称
    address = StringField(null=True)
    contacts = StringField(null=True)  # 联系方式
    emails = StringField(null=True)  # 订单邮箱
    book_tels = StringField(null=True)  # 预定电话
    customer_tels = StringField(null=True)  # 客服电话
    logo = StringField(null=True)  # logo图标
    pay_account_number = StringField(null=True)  # 付款账号
    pay_bank = StringField(null=True)  # 付款银行
    pay_name = StringField(null=True)  # 付款用户名

    bank_tel = StringField(null=True)  # 银行电话
    bank_address = StringField(null=True)  # 银行地址
    swift_code = StringField(null=True)
    routing_number = StringField(null=True)  # 银行路由编码

    remark = StringField(null=True)
    user_id = IntField(null=True)
    last_modified = DateTimeField(default=datetime.datetime.utcnow)
    date_added = DateTimeField(default=datetime.datetime.utcnow)

    destinations = ListField(ReferenceField(Destination))  # 供应商关联目的地

    meta = {
        'collection': 'vacation_supplier',
    }


class ProductDisplay(EmbeddedDocument):
    '''存的是markdown'''
    base_info = StringField(verbose_name=u'产品详情')
    price_info = StringField(verbose_name=u'价格信息')
    travel_time = StringField(verbose_name=u'行程时间表')
    agreement = StringField(verbose_name=u'预定须知')


class ProductSKU(BaseDocument):  # ProductType -> ProductSKU
    '''单品。类似淘宝京东里产品的套餐, 一个组合，应该拥有独立的price、retail_price'''
    name = StringField(verbose_name=u'名字', required=True)
    name_en = StringField(verbose_name=u'英文名')
    start_date = DateTimeField(verbose_name=u'开始时间')
    end_date = DateTimeField(verbose_name=u'结束时间')
    week_binary = IntField(verbose_name=u'可预订时间，按星期', default=1111111)
    blackoutdate = ListField(DateTimeField(verbose_name=u'不可用预订时间, 按日历'))

    fee = DecimalField(verbose_name=u'价格', precision=2)
    market_price = DecimalField(verbose_name=u'市场价', precision=2)
    adult_fee = DecimalField(verbose_name=u'成人价格', precision=2)
    adult_retail_fee = DecimalField(verbose_name=u'成人市场价', precision=2)
    adult_quotation = DecimalField(verbose_name=u'成人供应商报价', precision=2)
    description = StringField(verbose_name=u'成人说明')
    child_fee = DecimalField(verbose_name=u'儿童价格', precision=2)
    child_retail_fee = DecimalField(verbose_name=u'儿童市场价', precision=2)
    child_quotation = DecimalField(verbose_name=u'儿童供应商报价', precision=2)
    child_description = StringField(verbose_name=u'儿童说明')
    is_adult = BooleanField(verbose_name=u'是否成人/儿童', default=True)
    currency = StringField(verbose_name=u'币种', max_length=3, default='CNY')
    quotation_currency = StringField(verbose_name=u'供应商报价币种', max_length=3, default='CNY')
    is_default = BooleanField(default=False)  # 是否为默认, 需求：app进入预订产品页面时，默认选择的单品
    is_active = BooleanField(default=True)

    product = ReferenceField('Product', verbose_name=u'所属产品')
    # 下面这几个字段去掉了
    # exceed_fee = DecimalField(verbose_name=u'超员费用', max_digits=10, decimal_places=2)
    # normal = IntField(verbose_name=u'正常人数')
    # maximum = IntField(verbose_name=u'最大人数')
    # null_fee #现在不需要了，以前有null_fee值就不会有adult_fee和child_fee,迁移的时候null_fee就是adult_fee
    # null_retail_fee
    # is_null = models.BooleanField(default=False)

    meta = {
        'collection': 'vacation_productsku',
    }

    def get_price(self):
        return self.fee

    def get_market_price(self):
        """
        新dashboard 添加单品时，要保存market_price, 当前方法兼容旧数据, 旧数据用可以用脚本更新
        """
        if self.market_price:
            return self.market_price
        if self.adult_retail_fee:
            return self.adult_retail_fee
        if self.child_retail_fee:
            return self.child_retail_fee

    def as_dict(self, exclude=set(), only=set()):
        sku_dict = super(ProductSKU, self).as_dict(exclude=exclude, only=only)
        if isinstance(sku_dict['product'], Product):
            sku_dict['product'] = str(sku_dict['product'].id)

        sku_dict['total_price'] = self.get_price()
        return sku_dict

    def get_info(self, key):

        data = {
            'id': self.pk,
            'name_en': self.name_en,
            'currency': self.currency,
            # 'product_id': self.product.id, #TODO zezhou 解除注释
            # 'maximum': self.maximum,
            # 'normal': self.normal,
            'category': 0
        }
        if key == "adult" and self.is_adult:
            data['name'] = '%s(成人)' % smart_str(self.name) if \
                smart_str(u'成人') not in smart_str(self.name) else smart_str(self.name)
            data['fee'] = safe_int(self.adult_fee)
            data['retail_fee'] = float(
                self.adult_retail_fee) if self.adult_retail_fee else 0
            data['description'] = self.description
            data['category'] = 1
        # elif key == 'child' and self.is_child:
        elif key == 'child':
            data['name'] = '%s(儿童)' % smart_str(self.name) if \
                smart_str(u'儿童') not in smart_str(self.name) else smart_str(self.name)
            data['fee'] = safe_int(self.child_fee)
            data['retail_fee'] = float(
                self.adult_retail_fee) if self.adult_retail_fee else 0
            data['description'] = self.child_description
            data['category'] = 2
            # else:
            # data['name'] = self.name
            # data['fee'] = safe_int(self.null_fee)
            # data['retail_fee'] = float(
            #     self.null_retail_fee) if self.null_retail_fee else 0
            # data['description'] = self.description
            # data['category'] = 0
        return data


class Product(BaseDocument):
    """
    产品字段：
    一、基本信息
        1、(destination)目的地  —— 关联到自由行的目的地 [下拉选择]
        2、(name)名称  —— 文本型
        3、(name_en)英文名称  —— 文本型
        4、成人起价  —— 文本型
        5、成人市场价  —— 侧边栏封面展示，文本型
        6、耗时 —— 两个时段，文本型，单位下拉选择 (约2.5小时？)
        7、(service_language)服务语言（暂时客户端没用） —— 下拉选择
        8、(open_time)开放时间 —— 文本型
        9、(address)地址 —— 文本型
        10、(category)分类 —— 下拉选择
        11、筛选标签 —— 下拉选择
        12、(supplier)关联供应商  —— 下拉选择
        13、(arrival_type)到达方式 —— 文本型

    二、产品详情相关
        14、短描述--对应行程中的推荐理由，文本型
        15、(outline)推荐理由
            图片 —— 支持上传图片，展示链接
            文字 —— 文本输入框
        16、产品详情
        - (base_info)产品详情    支持预览
        - (price_info)价格信息    支持预览
        - (travel_time)行程时间表  支持预览
        - (agreement)预订须知    支持预览
        （以上字段支持跳转到用同一个编辑器，编辑并保存）

    三、产品类型相关
        17、产品类型（子产品）
        - 可预订时间（按星期）—— 勾选星期几
        - 不可预订时间（按日历）—— 日历
        - 中文名称 —— 文本型
        - 英文名称 —— 文本型
        - 开始时间 —— 文本型
        - 结束时间 —— 文本型
        - 成人价格 —— 文本型
        - 成人市场价格 —— 文本型
        - 成人报价 —— 文本型
        - 成人说明 —— 文本输入框
        - 儿童价格 —— 文本型
        - 儿童市场价格 —— 文本型
        - 儿童报价 —— 文本型
        - 儿童说明 —— 文本输入框
        18、产品类型的展示
        - 是否为默认类型（app预订的时候默认类型） —— 勾选


    四、价格信息和凭证展示
        19、(tour_inclusions)费用包含 —— 文本输入框
        20、(tour_exclusions)费用不包含 —— 文本输入框
        21、(usage_method)使用方法（出游凭证显示）—— 文本输入框
        22、(remind)特别提醒（凭证展示） —— 文本输入框


    五、预订页面相关
        23、最少提前几天预订 —— 时段，文本型
        24、最长可预订日期 —— 文本型
        25、可取消时间 —— 文本型
        26、(baby_description)携带婴儿说明（携带5周岁及以下婴儿(婴儿免费，但需告知)） —— 文本型
        27、酒店说明（接送酒店范围）—— 文本型

    六、供应商相关
        28、供应商确认信息
           - 是否使用面包凭证 —— 勾选
           - 候车时间 —— 勾选
           - 候车日期 —— 勾选
           - 供应商订单号 —— 勾选
           - 候车地点 —— 勾选
           - 快递单号 —— 勾选
           - logo图标 —— 勾选
           - 条形码 —— 勾选
           - 预约号 —— 勾选
           - 供应商名称 —— 勾选
        29、产品确认方式
            - 即时确认 —— 勾选
            - 二次确认 —— 勾选
            - [ ]小时内确认订单 —— 文本型

    七、其他杂项
        30、传图库- 支持上传图片，查看/排序，设置封面
        31、地图坐标/经纬度

    八、自定义部分 ** dynamic **
        一键勾选
        32、接机 —— 勾选
        33、送机 —— 勾选
        34、wifi —— 勾选
        35、电话卡 —— 勾选
        36、含接送服务 —— 勾选

        基本信息
        37、使用天数 —— 勾选
        38、新增一条

        备注信息
        39、使用日期
        40、航班号
        41、候车时间
        42、起飞时间
        43、抵达时间
        44、接送酒店
        45、酒店地址
        46、送达地点
        47、上车地点
        48、取票柜台
        49、邮寄地址
        50、婴儿数量
        （以上都是勾选）
        51、新增一条

        联系人信息
        52、中文姓名
        53、护照英文姓
        54、护照英文名
        55、性别
        56、联系人手机
        57、联系人邮箱
        58、微信号
        （以上都是勾选）
        59、新增一条
    """

    """
    产品编辑的时候很多可以为空,因为可能存草稿,但是在发布的时候不能为空
    """

    last_modified = DateTimeField(verbose_name=u'更新时间', default=datetime.datetime.utcnow)
    date_added = DateTimeField(verbose_name=u'创建时间', default=datetime.datetime.utcnow)
    is_active = BooleanField(verbose_name=u'是否启用', default=True)
    published = BooleanField(verbose_name=u'是否发布', default=False)
    is_push = BooleanField(verbose_name=u'是否xx', default=False)  # 记录产品是否可发布，已提交为可发布状态

    name = StringField(verbose_name=u'产品名', required=True)
    name_en = StringField(verbose_name=u'产品英文名')
    category_id = IntField(verbose_name=u'分类(枚举：景点、住宿、体验、餐饮、购物、交通)')
    destination = ReferenceField(Destination, verbose_name=u'目的地')  # 从面包旅行提供的api获取
    cover = URLField(verbose_name=u'封面')
    photos = StringField(verbose_name=u'图库')  # 存json
    address = StringField(verbose_name=u'地址')
    description = StringField(verbose_name=u'说明')
    open_time = StringField(verbose_name=u'开放时间')
    service_language = StringField(verbose_name=u'服务语言')
    arrival_type = StringField(verbose_name=u'到达方式')
    time_consuming_min = IntField(verbose_name=u'最小耗时')  # 耗时 单位：分钟
    time_consuming_max = IntField(verbose_name=u'最大耗时')

    currency = StringField(verbose_name=u'', max_length=3, default='CNY')
    fee = DecimalField(verbose_name=u'价格', precision=2)
    retail_fee = DecimalField(verbose_name=u'市场价', precision=2)

    outline = StringField(verbose_name=u'推荐理由(图片和文本)')

    supplier = ReferenceField(Supplier, verbose_name=u'供应商')  # 外键
    remark = StringField(verbose_name=u'备注')

    location = PointField(verbose_name=u'地理位置')

    classify = ReferenceField(Classify, verbose_name=u'筛选标签')  # 保险、WiFi、门票等

    # 价格信息和凭证展示
    tour_inclusions = StringField(verbose_name=u'费用包含')
    tour_exclusions = StringField(verbose_name=u'费用不包含')
    remind = StringField(verbose_name=u'特别提醒')
    usage_method = StringField(verbose_name=u'使用方法')

    start_delta = IntField(verbose_name=u'最少提前预定天数')
    start_time = StringField(verbose_name=u'xx点之前可以预定')  # 16:00之前可以预定, mongoengine没有time类型...所以存文本型，存储的时候加个验证
    close_date = DateTimeField(verbose_name=u'预定截止日期')  # mongoengine没有date类型，这里存datetime...
    cancel_hours = IntField(verbose_name=u'多少小时前可以取消')  # 可取消时间，单位：小时，-1代表不可取消, 0代表支持当天取消
    baby_description = StringField(verbose_name=u'携带婴儿说明')
    pick_range = StringField(verbose_name=u'接送范围')  # 即酒店说明

    is_paper_voucher = BooleanField(verbose_name=u'是否可以使用纸质凭证', default=False)
    is_sell_on_request = BooleanField(verbose_name=u'即时确认/二次确认', default=False)
    request_hours = IntField(verbose_name=u'订单二次确认时间')  # xx小时内确认订单

    product_display_info = EmbeddedDocumentField(ProductDisplay, default=ProductDisplay)
    productskus = ListField(ReferenceField(ProductSKU))

    supplier_confirm_option = ListField(StringField(verbose_name=u'供应商确认信息'))
    '''
    目前供应商确认信息字段包括(不存中文名)(有勾选就把英文字段append进list)：
      "is_voucher" 是否可以使用面包凭证
      "waiting_time" 侯车时间
      "waiting_date" 侯车日期
      "supplier_order_id" 供应商订单号
      "waiting_address" 候车地点
      "express_number" 快递单号
      "logo" logo图标
      "bar_code" 条形码
      "reservation_number" 预约号
      "supplier_name" 供应商名称
    '''
    product_custom_category = DictField(verbose_name=u'订单需要用户填写的信息')
    '''放json, 直接前端生成
        选项类型分为
              复选框类型(checkbox)
              自定义文本型(text)
              自定义选择型(select)

        其中婴儿数量is_baby、 使用天数use_days需要特殊处理。
    {
      'basic': [{}, {}, {}, ... ], #基本信息
      'extended': [{}, {}, {}, ... ], #备注/扩展信息
      'contact': [{}, {}, {}, ... ], #联系人信息
      "is_baby": false,
      "use_days": true
    }

    示例：
      {
      "extended": [
        {
          "sort": 1,
          "name": "使用日期",
          "url": "http://vacation.breadtrip.com/product/325/calendar/",
          "type": "url",
          "value": "",
          "name_en": "date",
          "placeholder": "使用日期"
        },
        {
          "sort": 3423,
          "name": "自取网点",
          "url": "",
          "placeholder": "",
          "value": [
            {
              "selected": true,
              "name": "sel0",
              "value": "北京市朝阳区京信大厦"
            },
            {
              "selected": false,
              "name": "sel1",
              "value": "北京首都机场T3国际出发"
            },
            ...,
          ],
          "name_en": "custom_3323",
          "type": "select"
        }
      ],
      "contact": [
        {
          "sort": 1,
          "name": "中文姓名",
          "url": "",
          "type": "text",
          "value": "",
          "name_en": "contact_name",
          "placeholder": "中文姓名"
        },
        {
          "sort": 5,
          "name": "联系人手机",
          "url": "",
          "type": "tel",
          "value": "",
          "name_en": "contact_tel",
          "placeholder": "联系人手机"
        },
        {
          "sort": 6,
          "name": "联系人邮箱",
          "url": "",
          "type": "email",
          "value": "",
          "name_en": "contact_email",
          "placeholder": "联系人邮箱"
        }
      ],
      "is_baby": false,
      "use_days": true
    }
    '''

    meta = {
        'collection': 'vacation_product',
    }

    # def get_info(self):
    #     items = {
    #         'id': self.pk,
    #         'name': self.name if self.name else self.poi.name,
    #         'poi': self.poi.get_info() if self.poi else None,
    #         'destination': self.destination.get_info(),
    #         'template': self.template.get_info(),
    #     }
    #     if self.pick_range:
    #         items['pick_range'] = self.pick_range
    #     return items

    def as_dict(self, exclude=set(), only=set()):
        dict_data = super(Product, self).as_dict(exclude=exclude, only=only)

        if isinstance(dict_data['supplier'], Supplier):
            dict_data['supplier'] = str(dict_data['supplier'].id)

        if isinstance(dict_data['destination'], Destination):
            dict_data['destination'] = str(dict_data['destination'].id)

        return dict_data

    def get_default_sku_as_dict(self):
        if not len(self.productskus):
            return {'error_message': u'该产品没有单品！请联系面包客服或管理人员'}

        skus = [sku for sku in self.productskus if sku.is_default]
        if len(skus):
            return skus[0].as_dict()
        else:
            return self.productskus[0].as_dict()

    def get_time_consuming(self):
        if self.time_consuming_min >= 1440 and self.time_consuming_min % 1440 == 0:
            start = self.time_consuming_min / 1440
            end = self.time_consuming_max / 1440
            unit = 1440
        elif self.time_consuming_min >= 60 and self.time_consuming_min % 60 == 0:
            start = self.time_consuming_min / 60
            end = self.time_consuming_max / 60
            unit = 60
        else:
            start = self.time_consuming_min
            end = self.time_consuming_max
            unit = 1
        return {
            'time_consuming_min': start,
            'time_consuming_max': end,
            'time_unit': unit,
        }

    # @queryset_manager
    def get_api_info(self, request=None):
        from app.controllers import get_mtu_comments

        photos = json.loads(self.photos) if self.photos else []

        """
        你们不需要了
        樊韩  10:08:31
        你们就用产品的photos就行
        樊韩  10:08:54
        这个是一开始的策略，现在不关联poi了，这个地方没必要做了
        """
        # poi = get_object_or_None(Poi, pk=self.poi_id)
        # if len(photos) < 5:
        #     try:
        #         poi_ids = json.loads(self.link_pois)
        #         link_poi = Poi.objects.filter(pk__in=poi_ids)[0]
        #     except:
        #         try:
        #             link_poi = get_object_or_None(Poi, pk=self.link_pois)
        #         except:
        #             link_poi = None
        #     link_poi = link_poi if link_poi else poi
        #     if link_poi:
        #         items = []
        #         obj = query_site_object(5 - len(photos), link_poi.pk)
        #         if obj:
        #             waypoints = get_favorite_waypoints(
        #                 obj, limit=4 - len(photos), offset=0)
        #             waypoints = waypoints['items']
        #             waypoints = get_waypoints_light(waypoints).values()

        #             # compress result
        #             items.extend([compressed_dict(x, ('photo_s'))
        #                           for x in waypoints])
        #             for item in items:
        #                 photos.append(item['photo_s'])
        photos = photos[:5]
        images = []
        outline = json.loads(self.outline) if self.outline else {}
        images.append({
            'description': outline.get('text'),
            'images': [outline['image']],
        })
        mtu = Mtu.objects.filter(target_id=str(self.pk)).first()
        ret = get_mtu_comments(mtu, start=0, count=1)

        # if mtu.target_type == MTU_TYPE.POI:
        #     target_id = mtu.target_id
        # else:
        #     target_id = 0
        #     p = Product.objects(pk=mtu.target_id)
        #     poi = p.poi
        #     if poi:
        #         target_id = poi.pk
        # dialogs_count = PoiDialog.objects.filter(
        #     poi__id=target_id, is_active=True).count()
        _lng, _lat = self.location['coordinates'] if self.location else (None, None)
        return {
            'mtu_id': str(mtu.pk) if mtu else None,
            # 'id': id_encrypt(self.pk),
            'id': str(self.pk),
            'name': self.name,
            'name_en': self.name_en,
            'time_consuming_min': self.time_consuming_min,
            'time_consuming_max': self.time_consuming_max,
            'fee': self.fee,
            'currency': '¥',
            'opening_time': self.open_time,
            'arrival_type': self.arrival_type,
            'images': images,
            'address': self.address,
            'latitude': _lat,
            'longitude': _lng,
            'base_info': bool(self.product_display_info.base_info),
            'price_info': bool(self.product_display_info.price_info),
            'travel_time': bool(self.product_display_info.travel_time),
            'detail': bool(self.product_display_info.agreement),
            # 'is_set_hotel': True if self.template_id in (2, 3, 4) else None,
            'small_covers': photos[:5],
            'cover': self.cover,
            'tip': ret.get('tips')[0] if ret.get('tips') else None,
            'recommended_reason': self.description,
            'destination_id': str(self.destination.pk),
            'product_id': str(self.pk),
            # 'poi_id': poi.pk if poi else None,
            'tips_count': ret.get('total_count'),
            # 'dialogs_count': dialogs_count,
            'category_id': self.category_id,
        }

        # def publish(self, published):
        #     from vacation.bt_utils import create_or_update_bt_product
        #     ptypes = ProductType.objects.filter(product=self, is_active=True)[:1]
        #     if self.published and not published:
        #         self.published = published
        #         self.save()
        #         if ptypes and self.bt_product_id:
        #             create_or_update_bt_product(self)
        #         return {
        #             'status': 'success',
        #             'message': u'取消发布成功',
        #         }

        #     message = u'没有产品类型，不能发布' if not ptypes else None
        #     message = message if self.fee else u'没有成人起价, 不能发布'
        #     message = message if self.supplier else u'没有关联供应商, 不能发布'

        #     if message:
        #         return {
        #             'status': 'error',
        #             'message': message,
        #         }
        #     self.published = published
        #     self.save()
        #     create_or_update_bt_product(self)
        #     return {
        #         'status': 'success',
        #         'message': u'发布成功',
        #     }

        # def delete(self):
        #     from vacation.bt_utils import create_or_update_bt_product
        #     self.is_active = False
        #     self.published = False
        #     self.save()

        #     if self.bt_product_id:
        #         create_or_update_bt_product(self)
        #     return

        # def is_multiplayer(self):
        #     ptypes = ProductType.objects.filter(
        #             product=self, is_active=True).order_by('-is_default')[:1]
        #     return True if ptypes and ptypes[0].is_multiplayer else False
